using System;
using System.Collections.Generic;
using System.Text;
using Microblaze.Simulator.Engine;

using Weazel.Gezel.Simulator.Reference.IpBlocks;
using Weazel.Microblaze.Simulator.Engine;
using Weazel.Microblaze.Simulator.Components.Opb;

namespace Weazel.Microblaze.Simulator.Components.Gezel
{
    public class GezelOpbSlave : IOpbSlave
    {
        private OpbGezelComponent parent;
        private OpbSlave ipBlock;

        private Opb.Opb opb;
        public Opb.Opb Opb
        {
            get { return opb; }
            set { opb = value; }
        }

        public uint LowAddress
        {
            get { return ipBlock.LowAddress; }
        }

        public uint HighAddress
        {
            get { return ipBlock.HighAddress; }
        }

        public GezelOpbSlave(OpbGezelComponent parent, OpbSlave ipBlock)
        {
            this.parent = parent;
            this.ipBlock = ipBlock;
        }

        public void Load(byte[] bytes, uint address)
        {
            throw new NotSupportedException("Load() not supported for Gezel components");
        }

        private Transaction currentTransaction;

        public void SetupTransaction(Transaction transaction)
        {
            this.currentTransaction = transaction;

            if (transaction.Type == Transaction.TransactionType.Read)
            {
                ipBlock.OpbAddressBus = transaction.Address;
                ipBlock.OpbReadNotWrite = true;
                ipBlock.OpbSelect = true;
            }
            else if (transaction.Type == Transaction.TransactionType.Write)
            {
                ipBlock.OpbDataBus = transaction.Value;
                ipBlock.OpbAddressBus = transaction.Address;
                ipBlock.OpbReadNotWrite = true;
                ipBlock.OpbSelect = true;
            }
        }

        public bool EvaluateTransaction()
        {
            if (ipBlock.SlaveXferAck == true)
            {
                if (currentTransaction.Type == Transaction.TransactionType.Read)
                {
                    currentTransaction.Value = ipBlock.SlaveDataBus;
                }
                else if (currentTransaction.Type == Transaction.TransactionType.Write)
                {
                    // nothing
                }

                currentTransaction.Status = Transaction.TransactionStatus.Complete;
                return true;
            }

            return false;
        }

        public void BeginIdleTransaction()
        {
            parent.StepSimulation();
        }

        public void BeginTransaction(Transaction transaction)                
        {
            SetupTransaction(transaction);
            parent.StepSimulation();
            EvaluateTransaction();
        }
    }
}


            /*
          uint mask = addressToBitSelect(address);

          // assert the read signal
          gezelIpBlock.WriteBus2IP_RdCE(mask);

          // step simulation
          simulator.StepGezelSimulation();

          // clear signals (may be overwritten later if needed)
          gezelIpBlock.WriteBus2IP_RdCE(0);

          // only read the data is the "ack" signal is asserted
          uint result = (gezelIpBlock.ReadIP2Bus_Ack() == 1) ?
              gezelIpBlock.ReadIP2Bus_Data()
            : 0;

          string str = 
            string.Format("rd cycle: {0,10} address: 0x{1,8:X8} value: 0x{2,8:X8}", 
              simulator.GezelSimulation.Cycle - 1, 
              address, 
              result
            );

          simulator.OpbIpifOutputWriter.WriteLine(str);

          value = result;
             * */



        /*
uint mask = addressToBitSelect(address);

// assert the write signal
gezelIpBlock.WriteBus2IP_WrCE(mask);
gezelIpBlock.WriteBus2IP_Data(word);

// step simulation
simulator.StepGezelSimulation();

// clear signals (may be overwritten later if needed)
gezelIpBlock.WriteBus2IP_WrCE(0);
gezelIpBlock.WriteBus2IP_Data(0);

string str =
string.Format("wr cycle: {0,10} address: 0x{1,8:X8} value: 0x{2,8:X8}",
simulator.GezelSimulation.Cycle - 1,
address,
word
);

simulator.OpbIpifOutputWriter.WriteLine(str);
*/

